package com.blb.edupayservice.service.impl;

import com.blb.common.entity.UserCourseOrder;
import com.blb.edupayservice.config.MyWXPayConfig;
import com.blb.edupayservice.config.TimeoutOrderMQConfig;
import com.blb.edupayservice.feign.CourseServiceFeignClient;
import com.blb.edupayservice.feign.OrderServiceFeignClient;
import com.blb.edupayservice.service.WxPayService;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.util.Streams;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 微信支付的实现
 */
@Slf4j
@Service
public class WxPayServiceImpl implements WxPayService {

    //应用类型
    public static final String DEVICE_INFO = "WEB";
    //商户的名称
    public static final String BODY = "在线教育";
    //货币类型
    public static final String FEE_TYPE = "CNY";
    //支付成功回调接口的URL，内网测试时需要配置内网穿透
    public static final String NOTIFY_URL = "http://xj7gat.natappfree.cc/wxpay/callback";
    //交易类型 NATIVE 本地二维码
    public static final String TRADE_TYPE = "NATIVE";
    //签名
    public static final String SIGN = "5E00F9F72173C9449F802411E36208734B8138870ED3F66D8E2821D55B317078";

    @Resource
    private CourseServiceFeignClient courseServiceFeignClient;

    @Resource
    private OrderServiceFeignClient orderServiceFeignClient;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @GlobalTransactional
    @Override
    public Map<String, String> makeOrder(Long userId, Long courseId, Long price) throws Exception {
        //创建微信配置对象
        MyWXPayConfig config = new MyWXPayConfig();
        //创建微信支付对象
        WXPay wxPay = new WXPay(config);
        //调用微信的统一下单api
        Map<String, String> map = new HashMap<>();
        map.put("appid", config.getAppID());
        map.put("mch_id", config.getMchID());
        map.put("device_info", DEVICE_INFO);
        map.put("nonce_str", WXPayUtil.generateNonceStr());
        map.put("body", BODY);
        //创建随机订单号
        String tradeNo = UUID.randomUUID().toString().replace("-", "");
        map.put("out_trade_no", tradeNo);
        map.put("fee_type", FEE_TYPE);
        //价格
        map.put("total_fee", String.valueOf(price));
        //微信对商户后台的回调接口，更新订单状态
        map.put("notify_url", NOTIFY_URL);
        map.put("trade_type", TRADE_TYPE);
        map.put("product_id", String.valueOf(courseId));
        //返回下单结果
        Map<String,String> result = wxPay.unifiedOrder(map);
        if(result != null && "SUCCESS".equals(result.get("result_code"))){
            String codeUrl = result.get("code_url");
            log.info("code_url:{}",codeUrl);
            result.put("trade_no",tradeNo);
            //调用订单服务，在订单表插入订单
            //创建课程订单--调用订单服务的插入接口
            long id = System.currentTimeMillis();
            Timestamp now = Timestamp.valueOf(LocalDateTime.now());
            UserCourseOrder order = new UserCourseOrder(id,userId,courseId,1L,0L,tradeNo,price,now,now,0L);
            orderServiceFeignClient.makeOrder(order);
            //增加课程销量 -- 调用课程服务的接口
            courseServiceFeignClient.addCourseSales(order.getCourseId());
            //超时订单处理，查询支付结果，修改订单状态
            rabbitTemplate.convertAndSend(TimeoutOrderMQConfig.ORDER_EXCHANGE,TimeoutOrderMQConfig.ORDER_QUEUE_KEY,tradeNo,
                    //消息的后置处理
                    message -> {
                        message.getMessageProperties().setMessageId(UUID.randomUUID().toString());
                        //设置消息超时
                        message.getMessageProperties().setExpiration(String.valueOf(60 * 1000));
                        return message;
                    });
        }
        return result;
    }


    /**
     * 生成二维码
     */
    @Override
    public void makeQRCode(String url, HttpServletResponse response) throws Exception {
        //通过支付链接生成二维码
        HashMap<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        hints.put(EncodeHintType.MARGIN, 2);
        //把code_url包装到二维码图片
        BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 200, 200, hints);
        MatrixToImageWriter.writeToStream(bitMatrix, "PNG", response.getOutputStream());
        log.info("创建二维码完成");
}

    @Override
    public String checkOrder(String tradeNo) throws Exception {
        MyWXPayConfig config = new MyWXPayConfig();
        WXPay pay = new WXPay(config);
        Map<String, String> map = new HashMap<>();
        map.put("appid",config.getAppID());
        map.put("mch_id", config.getMchID());
        map.put("nonce_str", WXPayUtil.generateNonceStr());
        map.put("out_trade_no", tradeNo);
        map.put("sign",SIGN);
        //到微信平台查询订单
        Map<String, String> res = pay.orderQuery(map);
        String state = res.get("trade_state");
        log.info("订单" + tradeNo + ",状态" + state);
        return state;
    }

    @Override
    public void payCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //获得微信传来的xml字符串
        String str = Streams.asString(request.getInputStream());
        //将字符串xml转换为Map
        Map<String, String> map = WXPayUtil.xmlToMap(str);
        //给微信后台发送消息
        response.getWriter().println("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
        //读取订单号
        String tradeNo = map.get("out_trade_no");
        log.info("支付成功：{}",tradeNo);
        //查询微信后台订单的状态
        String status = checkOrder(tradeNo);
        if("SUCCESS".equals(status)) {
            //查询课程id --调用订单服务接口通过订单号查询订单（课程id）
            ResponseEntity<UserCourseOrder> entity = orderServiceFeignClient.getOrderByTradeNo(tradeNo);
            UserCourseOrder order = entity.getBody();
            //修改订单状态 --调用订单服务接口
            order.setStatus(1);
            orderServiceFeignClient.changeOrderStatus(order);
        }
    }

    @GlobalTransactional
    @Override
    public void cancelOrder(String tradeNo) {
        //按订单号查询订单
        ResponseEntity<UserCourseOrder> orderEntity = orderServiceFeignClient.getOrderByTradeNo(tradeNo);
        UserCourseOrder order = orderEntity.getBody();
        //如果订单没有支付，修改订单状态
        if(order.getStatus() == 0) {
            //将订单状态改为取消2
            order.setStatus(2);
            orderServiceFeignClient.changeOrderStatus(order);
//            int x = 10 / 0;
            //将课程销量减一
            courseServiceFeignClient.reduceCourseSales(order.getCourseId());
            log.info("取消订单处理完成{}",tradeNo);
        }
        log.info("超时订单处理完成{}",tradeNo);
    }
}
